package middleware // 声明为middleware包

import (
	"context"                 // 上下文管理
	"encoding/json"           // JSON编解码
	"fmt"                     // 格式化输出
	"novel-go/global"         // 全局变量
	"novel-go/model/request"  // 请求模型
	"novel-go/model/response" // 响应模型
	"time"                    // 时间处理

	"novel-go/utils" // 工具函数

	"github.com/go-redis/redis/v8" // Redis客户端
	"go.uber.org/zap"              // 日志记录
)

// 定义API服务处理函数类型
// 参数：*request.Request 请求对象
// 返回值：(状态码, 响应数据)
type ApiServiceHandler func(req *request.Request) (code int, data interface{})

// CacheMemoize - 缓存API响应数据的中间件
// 参数：
//
//	f: 原始API处理函数
//	timeout: 缓存超时时间(秒)
//	req: 请求对象
//
// 返回值：
//
//	(状态码, 响应数据)
func CacheMemoize(f ApiServiceHandler, timeout int64, req *request.Request) (code int, data interface{}) {
	// 1. 生成缓存键
	jsonData, _ := json.Marshal(req.Data)                           // 序列化请求数据
	key := fmt.Sprintf("%s_%s", req.Action, utils.GetMd5(jsonData)) // 格式: action_md5(data)

	var ctx = context.Background() // 创建上下文

	// 2. 尝试从Redis获取缓存
	val, err := global.FPG_REIDS.Get(ctx, key).Result()
	if err != nil {
		// 缓存不存在或出错
		if err != redis.Nil { // 忽略"key不存在"的错误
			global.FPG_LOG.Error("get cache error", zap.Error(err))
		}
	} else {
		// 3. 缓存命中，解析缓存值
		var res response.Response
		// 将val转化为 byte 切片，并赋值给res.Data
		err = json.Unmarshal([]byte(val), &res)
		if err != nil {
			global.FPG_LOG.Error("json parse error", zap.Error(err))
		} else {
			return res.Code, res.Data // 直接返回缓存结果
		}
	}

	// 4. 缓存未命中，调用原始函数
	var res response.Response
	res.Code, res.Data = f(req) // 执行实际业务逻辑

	// 5. 缓存成功响应
	jsonData, _ = json.Marshal(res)
	if res.Code == response.Success { // 只缓存成功响应
		err = global.FPG_REIDS.Set(ctx, key, string(jsonData),
			time.Second*time.Duration(timeout)).Err()
		if err != nil {
			global.FPG_LOG.Error("set cache error", zap.Error(err))
		}
	}

	return res.Code, res.Data
}
